#!/usr/bin/perl
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
#  
#  
# Licensed Materials - Property of IBM 
#  
# (C) COPYRIGHT International Business Machines Corp. 2000,2004 
# All Rights Reserved 
#  
# US Government Users Restricted Rights - Use, duplication or 
# disclosure restricted by GSA ADP Schedule Contract with IBM Corp. 
#  
# IBM_PROLOG_END_TAG 
# @(#)85   1.22   src/csm/core/cmds/mgmtsvr.perl, csmcore, csm_rameh, rameh0431a 4/13/04 00:02:18

use strict;
use locale;
BEGIN
  {
	# this enables us to redirect where it looks for other CSM files during development
	$::csmroot = $ENV{'CSM_ROOT'} ? $ENV{'CSM_ROOT'} : '/opt/csm';
	$::csmpm = "$::csmroot/pm";
	$::csmbin = "$::csmroot/bin";
  }
use lib $::csmpm;
use Getopt::Std;
require NodeUtils;

# For the usage, see nodecmds.msg
sub usage { NodeUtils->message('I', 'IMsgMgmtsvrUsage');  exit (scalar(@_) ? $_[0] : 1); }

$::MSGCAT = 'nodecmds.cat';
$::MSGMAPPATH = "$::csmroot/msgmaps";

# Parse the cmd line args and check them
if (! getopts('n:NhvVdkH:') ) { &usage; }
if ($::opt_h) { &usage(0); }
if (scalar(@ARGV) > 1) { &usage; }
#Now allow -d & -N to be used with ARGV
#if (scalar(@ARGV) > 0 && ($::opt_d||$::opt_N)) { &usage; }
if (scalar(@ARGV) == 0 && defined($::opt_n)) { &usage; }

if ( defined($::opt_n) ) {
  &waitForCTRMC( );
}

$::VERBOSE = $::opt_v || $::opt_V ;
$ENV{'CT_MANAGEMENT_SCOPE'} = 1;      # set local scope because we only want the local Management Server class
delete $ENV{'CT_CONTACT'};

if($::opt_H){ #set HA management server
  &setHAMS();
  exit;
}

if (scalar(@ARGV) > 0)     # they are setting the mgmt svr
  {
      my $ms = shift @ARGV;
      if(!$ENV{'CSM_MAKENODE_RUNNING'}){
	  # Should we do this or not?  If this name came from the mgmt svr, it might be better to use it
	  # exactly.  If it came from the cmd line on the node, we should try name resolution.
	  $ms = NodeUtils->tryHost($ms);
      }
	#my $ms = shift @ARGV;
	#print "opt_n=$::opt_n\n";
	if($::opt_d){ #just delete this ms
		&rmMgmtSvr($ms);	
	}
	elsif($::opt_n){
		&setMgmtSvr($ms, $::opt_n);
	}
	else{ #just display ms
		&displayMS($ms);
	}
  }
elsif ($::opt_d)      # they are removing the mgmt svr
  {
	&rmMgmtSvr();
  }
elsif (!$::opt_d)       # display ALL mgmt svrs
  {
	&displayMS();
  }


exit;


# Return true if this machine is the mgmt svr for itself.
sub isOwnMgmtSvr
  {
	my ($ms, $lhn) = @_;

	# If this is a mgmt svr for itself then we should be able to look up the $lhn in the ManagedNode
	# class and the ManagementServer attribute should match $ms.
	my $outref = NodeUtils->runrmccmd('lsrsrc-api', "-i -D ':|:'", qq(-s IBM.ManagedNode::"Hostname='$lhn'"::ManagementServer));
	if (scalar(@$outref) == 0) { return 0; }
	return $$outref[0] eq $ms;
  }


# Return the mgmt svr and local hostname from the IBM.ManagementServer resource class.
# This function assumes we are on a node.
sub getMgmtSvr
  {
	my ($name) = @_; #if they specify a ms name 
	my $outref;
	my %MgmtSvrs;
	if($name){
		$outref = NodeUtils->runrmccmd('lsrsrc-api', "-i -D ':|:'", qq(-s IBM.ManagementServer::"ManagerType='CSM' && Hostname='$name'"::LocalHostname::HAState));
	}
	else{ 
		$outref = NodeUtils->runrmccmd('lsrsrc-api', "-i -D ':|:'", qq(-s IBM.ManagementServer::"ManagerType='CSM'"::Hostname::LocalHostname::HAState));
	}
	if (scalar(@$outref) == 0) { return; }
	foreach my $line (@$outref){ #there can be multiple ms defined	
		my ($ms, $lhn, $state) = split(/:\|:/, $line);
		$MgmtSvrs{$ms}=$lhn;
		$::MHAState{$ms}= $state;	
	}
	return (\%MgmtSvrs);
  }


sub setMgmtSvr
  {
    my ($ms, $lhn) = @_;
    
    if (!NodeUtils->isNode()) { NodeUtils->message('E41','EMsgNOT_A_NODE'); }
    
    my $cmd;
    my $changedHostname = 1;     # used to know if we need to refresh at the end
    # See if there is already an entry - if so, replace it
    my $MgmtSvrs = &getMgmtSvr();
    my @servers = keys %$MgmtSvrs;
    foreach my $prevms (@servers){
      my $prevlhn = $$MgmtSvrs{$prevms};
      if ($ms ne $prevms)   # the Hostname has changed
	{
	  # Undefine the resource and recreate it.  This is necessary to get the DMSRM to go
	  # through the full processing in the case that this is really a new mgmt svr.  In the
	  # case in which this is the same mgmt svr with a name change, this will also be ok.
	  NodeUtils->runrmccmd('rmrsrc-api', '', qq(-s IBM.ManagementServer::"Hostname='$prevms'"));
	  my $attr2 = length($lhn) ? qq(::LocalHostname::"$lhn") : '';
	  NodeUtils->runrmccmd('mkrsrc-api', '', qq(IBM.ManagementServer::Hostname::"$ms"::ManagerType::"CSM"$attr2));
	}
      elsif (length($lhn) && $lhn ne $prevlhn)   # Hostname did not change, but LocalHostname did
	{
	  # Note: we don't need to process the -k option in this case because the
	  #       ManagementServer resource class will exchange keys if either attribute
	  #       changed.
	  
	  NodeUtils->runrmccmd('chrsrc-api', '', qq(-s IBM.ManagementServer::"Hostname='$prevms'"::LocalHostname::"$lhn"));
	  #my $opflag = '0';
	  #NodeUtils->runrmccmd('runact', '', qq(-c IBM.ManagementServer RefreshNodeInfo MgmtSvrHostname=$ms OperationFlag=$opflag));
	  #todo: handle the no resources found error in case the resource was deleted after we checked it above.
	}
      elsif($::opt_k)         # no need to change the resource but need to run the refresh action
	{
	  $changedHostname = 0;
	  my $opflag = '0';
	  #NodeUtils->runrmccmd('runact', '', qq(-c IBM.ManagementServer RefreshNodeInfo MgmtSvrHostname=$ms OperationFlag=$opflag));
	  NodeUtils->runrmccmd('runact-api', '', qq(-c IBM.ManagementServer::::RefreshNodeInfo::MgmtSvrHostname::"$ms"::OperationFlag::"$opflag"));
	}
    }
    if(scalar (keys %$MgmtSvrs) ==0)						# create the entry
      {
	my $attr2 = length($lhn) ? qq(::LocalHostname::"$lhn") : '';
	NodeUtils->runrmccmd('mkrsrc-api', '', qq(IBM.ManagementServer::Hostname::"$ms"::ManagerType::"CSM"$attr2));
      }
        
    # Refresh the rmc daemon so it picks up the acl file that was possibly modified as a
    # result of changing the management server
    if ($changedHostname) { NodeUtils->runrmccmd('refresh', '-s ctrmc'); }
  }


sub rmMgmtSvr
  {
	my ($server) = @_;
	if (!NodeUtils->isNode()) { NodeUtils->message('E41','EMsgNOT_A_NODE'); }
	#my ($ms, $lhn) = &getMgmtSvr();
	my $MgmtSvrs = &getMgmtSvr();
	foreach my $ms (keys %$MgmtSvrs){
		if($server && $ms ne $server){ next; }
		if (length($ms)){ 
			NodeUtils->runrmccmd('rmrsrc-api', '-i', qq(-s IBM.ManagementServer::"Hostname='$ms'"));
		}
	}
  }


# This is not currently used
#sub checkMgmtSvr
#  {
#	my ($class, $force) = @_;
#	my $ms = NodeUtils->getMgmtSvr($force);
#	if (length($ms))       # we are on a node
#	  {
#		# Set the environment var so RMC will connect remotely
#		NodeUtils->msg($msgs, 'V', 'CONNECTING_REMOTELY', $ms);
#		$ENV{'CT_CONTACT'} = $ms;
#	  }
#  }


sub isCTRMCrunning
  {
        my @output = NodeUtils->runcmd("LANG=C /usr/bin/lssrc -s ctrmc", -1);
        if ($::RUNCMD_RC) { return 0; }   # maybe we should try to catch real errors here
        my ($subsys, $group, $pid, $status) = split(' ', $output[1]);
        if (defined($status) && $status eq 'active') { 
		#now check to see if IBM.CSMAgentRM is up
		@output = NodeUtils->runcmd("LANG=C /usr/bin/lssrc -s IBM.CSMAgentRM", -1);
		if ($::RUNCMD_RC) { return 0; }   # maybe we should try to catch real errors here
        	($subsys, $group, $pid, $status) = split(' ', $output[1]);
        	if (defined($status) && $status eq 'active') { 
		    return 1; 
		}
		else { return 0; }
	}
        else { return 0; }
  }


sub waitForCTRMC
  {
        # Wait for the ctrmc and IBM.CSMAgentRM daemons to start. ctrmc will start CSMAgentRM
        # This is important during the first boot of a machine when ctrmc must
        # get started from /etc/inittab before mgmtsvr is successful.
        my $i;
        for ($i=1; $i<=15; $i++)
          {
                if (&isCTRMCrunning())
                  {
			  last;
                  }
                sleep 2;
          }
        if ($i > 14) { NodeUtils->message('W', 'EMsgDAEMON_NOT_STARTED', "ctrmc" ); }
  }

sub displayMS{
	# These are the various cases:
	# - only a node, mgmt svr set - rc=0, display: foo.com
	# - only a node, mgmt svr not set - rc=11, display: This node does not currently have....
	# - mgmt svr/node, mgmt svr set to self - rc=21, display: foo.com (This node is the mgmt svr for itself.)
	# - mgmt svr/node, mgmt svr set to other mgmt svr - rc=22, display: foo.com (This node is also a mgmt svr for other nodes.)
	# - mgmt svr/node, mgmt svr not set - rc=23, display: This machine is a CSM mgmt svr and a node, but the node does not currently...
	# - only a mgmt svr - rc=31, display: This machine is a CSM management server.
	# - more than 1 mgmt svr defined on this node - rc=31, display: This machine has multiple management servers:\nfoo.com\nbar.com
	# - neither a mgmt svr or a node - rc=101, display: This machine is neither a CSM mgmt svr or node.
	
	my ($ms) = @_;
	if (NodeUtils->isNode())
	  {
		my $MgmtSvrs = &getMgmtSvr($ms);
		my $numkeys = keys %$MgmtSvrs;
		if(keys %$MgmtSvrs <= 1){ #only 1 MS defined
			my @all = keys %$MgmtSvrs;
			my $ms = $all[0];
			my $lhn = $$MgmtSvrs{$ms};
			if ($::opt_N) { NodeUtils->message('O','IMsgMS_AND_LHN', $ms, $lhn); }
			elsif (!NodeUtils->isMgmtSvr())
			  {
				if (length($ms)) { print "$ms\n"; }
				else { NodeUtils->message('I11','IMsgNOT_SET'); }
			  }
			else         # also a mgmt svr
			  {
				if (length($ms))
				  {
					if (&isOwnMgmtSvr($ms, $lhn)) { NodeUtils->message('I21','IMsgBOTH_ITSELF', $ms); }
					else { NodeUtils->message('I22','IMsgBOTH_OTHER', $ms); }
				  }
				else { NodeUtils->message('I23','IMsgBOTH_NOT_SET'); }
			  }
		  }
		  else{ #more than 1 MS defined
			my @servers = keys %$MgmtSvrs;
			print "There are multiple management servers defined for this node:\n";
			foreach my $ms (@servers){
				if($::opt_N){
					my $lhn = $$MgmtSvrs{$ms};
					NodeUtils->message('O','IMsgMS_AND_LHN', $ms, $lhn);
				}
				else{
					print "$ms\n";
				}
			}
			exit 41;
	  	}
	  }
	elsif (NodeUtils->isMgmtSvr())   # only a mgmt svr
	  { NodeUtils->message('I31','IMsgMGMT_SVR'); }
	else       # neither a node or mgmt svr (must only have csm.core installed)
	  { NodeUtils->message('E101','EMsgNEITHER'); }	
	
}

sub setHAMS{

  my $configinfo = "/opt/csm/install/configinfo";
  my $hostname;
  if(-e $configinfo){
    open (CONFIG, $configinfo) or die "cannot open $configinfo: $!";
    while(my $line = <CONFIG>){ 
      chomp $line;
      if($line =~ /^Hostname=(.*)/){
	$hostname = $1;
	last;
      }
    }
    close CONFIG;
    my $ms = $::opt_H;
    my $state=0;
    if(@ARGV){ $state=1; }
    my $MgmtSvrs = &getMgmtSvr();
    my @servers = keys %$MgmtSvrs;
    my $made =0;
    foreach my $exist_ms (@servers){
      if($exist_ms eq $ms){
	if(($hostname ne $$MgmtSvrs{$ms}) || ($::MHAState{$ms} != $state)){
	  #remove it
	  NodeUtils->runrmccmd('rmrsrc-api', '', qq(-s IBM.ManagementServer::"Hostname='$ms'"));
	}
	else{
	  $made=1;
	  }
      }
    }
    if(!$made){
      NodeUtils->runrmccmd('mkrsrc-api', '', qq(IBM.ManagementServer::Hostname::"$ms"::ManagerType::"CSM"::LocalHostname::${hostname}::HAState::$state));
    }
  }
}

